
from authority.user import AuthorityUser

from authority.methods import HTTPBasicAuthMethod, AuthFormMethod
from authority.checkers import MatchChecker

from authority.utils import load_ep_from_group

import logging
log = logging.getLogger(__name__)

class AuthorityScheme(object):
    '''Base class for Authority authentication schemes.
    
    '''
    
    def __init__(self, method=None, checker=None, provider=None, options=None):
        '''Initialize the scheme.'''
        options = options or {}
        
        self.options = options

        self._create_component_configs()

        self.method = method
        self.checker = checker
        self.provider = provider
        
        # subclasses should call self.after_init() at the END of 
        # their __init__ method! e.g.:
        #self.after_init()

    def after_init(self):
        '''Perform post-initialization tasks.
        
        '''
        # attach a reference to the scheme to each component
        for obj in [self.method, self.checker, self.provider]:
            if obj:
                obj.scheme = self

    def _create_component_configs(self):
        '''Create options dictionaries for individual auth components.
        
        This method creates and populates options dicts for the individual 
        components of the scheme from the main scheme options dictionary.
        '''
        self.method_opts  = {} 
        if 'method_opts' in self.options:
            self.method_opts = self.options['method_opts']
        self.checker_opts = {}
        if 'checker_opts' in self.options:
            self.checker_opts = self.options['checker_opts']
        self.provider_opts = {}
        if 'provider_opts' in self.options:
            self.provider_opts = self.options['provider_opts']

    def prompt_user(self):
        '''Return a WSGI app which prompts the user for credentials.
        
        '''
        log.debug('prompting user for credentials')
        
        if self.method:
            wsgi_prompt = self.method.make_prompt()
            return wsgi_prompt

    def get_user(self):
        '''Get a user object from the authorization provider
        
        This method returns a user object from the scheme's provider.
        If there is no provider, a minimal user object (of the 
        AuthorityUser class) will be returned.
        '''
        if self.provider:
            return self.provider.get_user()
        return AuthorityUser()

    def authenticate(self, credentials):
        '''Check the users credentials
        
        Returns True if credentials are valid, otherwise returns false.
        '''
        if self.checker:
            return self.checker.check_credentials(credentials)
        
    def get_credentials(self, environ):
        '''Get user credentials out of the request
        
        Returns either of:
        - a dict containing the credentials
        - None
        '''
        if self.method:
            return self.method.get_credentials(environ)


class DynamicScheme(AuthorityScheme):
    '''Class that dynamically creates a Scheme
    
    expects method, checker, and provider to be strings
    '''
    def __init__(self, options=None):
        AuthorityScheme.__init__(self, options=options)
        
        grps = ('authority.methods', 
                'authority.checkers', 
                'authority.providers')
        
        log.debug('scheme set to auto...dynamically generating scheme')
        # TODO: these need to be in try blocks
        # ...and could probably just be a loop
        if self.options.has_key('method') and self.options['method']:
            log.debug('method: %s' % self.options['method'] )
            method_class = load_ep_from_group(grps[0], self.options['method']) 
            self.method = method_class(self.options['method_opts'])
            
        if self.options.has_key('checker') and self.options['checker']:
            log.debug('checker: %s' % self.options['checker'] )
            checker_class = load_ep_from_group(grps[1], self.options['checker']) 
            self.checker = checker_class(self.options['checker_opts'])
            
        if self.options.has_key('provider') and self.options['provider']:
            log.debug('provider: %s' % self.options['provider'] )
            provider_class = load_ep_from_group(grps[2], self.options['provider'])
            self.provider = provider_class(self.options['provider_opts'])
        
        log.debug('dynamic scheme method  : %s' % self.method)
        log.debug('dynamic scheme checker : %s' % self.checker)
        log.debug('dynamic scheme provider: %s' % self.provider)
        
        self.after_init()

class HTTPBasicMatchScheme(AuthorityScheme):
    '''Scheme which authenticates using HTTP Basic auth based on matching 
    usernames and passwords.
    
    method = httpbasic
    checker = match
    provider = None
    '''

    def __init__(self, options=None):
        AuthorityScheme.__init__(self, options=options)
            
        self.method = HTTPBasicAuthMethod(self.method_opts)
        self.checker = MatchChecker(self.checker_opts)
        self.provider = None
        
        self.after_init()

    #~ def _load_authmethod(self, method_opts):
        #~ return HTTPBasicAuthMethod()
        
class HTTPBasicHtpasswdScheme(AuthorityScheme):
    '''
    
    
    '''
    def __init__(self, options=None):
        raise NotImplementedError
        
class HTTPDigestMatchScheme(AuthorityScheme):
    '''
    
    
    '''
    def __init__(self, options=None):
        raise NotImplementedError

class AuthFormMatchScheme(AuthorityScheme):
    '''
    
    method = authform
    checker = match
    provider = None
    '''
    def __init__(self, options=None):
        AuthorityScheme.__init__(self, options=options)
        
        self.method = AuthFormMethod(self.method_opts)
        self.checker = MatchChecker(self.checker_opts)
        self.provider = None

        self.after_init()
